/*
 * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_mac.h" // For MACSTR and MAC2STR macros
#include "lwip/inet.h"
#if IP_NAPT
#include "lwip/lwip_napt.h"
#endif

/* AP Configuration */
// #define EXAMPLE_ESP_WIFI_AP_SSID            CONFIG_ESP_WIFI_AP_SSID
#define EXAMPLE_ESP_WIFI_AP_SSID            "ESP32-C3_AP"  // 热点名称
// #define EXAMPLE_ESP_WIFI_AP_PASSWD          CONFIG_ESP_WIFI_AP_PASSWORD
#define EXAMPLE_ESP_WIFI_AP_PASSWD          "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL            CONFIG_ESP_WIFI_AP_CHANNEL
#define EXAMPLE_MAX_STA_CONN                CONFIG_ESP_MAX_STA_CONN_AP

/*DHCP server option*/
#define DHCPS_OFFER_DNS             0x02

static const char *TAG_AP = "WiFi SoftAP";

/**
 * @brief Initialize soft AP
 *
 * @return esp_netif_t* Handle to the network interface
 */
/**
 * @brief 初始化ESP32的WiFi接入点(AP)模式
 * 
 * 该函数完成以下任务：
 * 1. 创建默认的WiFi接入点网络接口
 * 2. 配置AP的参数，包括SSID、密码、通道、最大连接数和认证模式
 * 3. 根据密码是否为空，自动选择开放式或WPA2-PSK认证方式
 * 4. 应用配置并记录初始化完成信息
 * 
 * @return esp_netif_t* 返回创建的WiFi接入点网络接口指针，供后续网络操作使用
 */
esp_netif_t *wifi_init_softap(void)
{
    // 创建默认的WiFi接入点网络接口
    esp_netif_t *esp_netif_ap = esp_netif_create_default_wifi_ap();

    // 配置WiFi接入点参数
    wifi_config_t wifi_ap_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_AP_SSID,          // AP名称（SSID）
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_AP_SSID), // SSID长度
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,       // WiFi通道号
            .password = EXAMPLE_ESP_WIFI_AP_PASSWD,    // AP密码
            .max_connection = EXAMPLE_MAX_STA_CONN,    // 最大STA连接数
            .authmode = WIFI_AUTH_WPA2_PSK,            // 默认使用WPA2-PSK认证
            .pmf_cfg = {                               // PMF(保护管理帧)配置
                .required = false,                     // 不强制要求PMF
            },
        },
    };

    // 如果密码为空字符串，则设置为开放网络（无需密码）
    if (strlen(EXAMPLE_ESP_WIFI_AP_PASSWD) == 0) {
        wifi_ap_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    // 将配置应用到WiFi接入点接口
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config));

    // 记录接入点初始化完成信息，包括SSID、密码和通道号
    ESP_LOGI(TAG_AP, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             EXAMPLE_ESP_WIFI_AP_SSID, EXAMPLE_ESP_WIFI_AP_PASSWD, EXAMPLE_ESP_WIFI_CHANNEL);

    // 返回创建的网络接口指针，供其他函数使用
    return esp_netif_ap;
}

/**
 * @brief WiFi AP event handler
 */
static void wifi_ap_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *) event_data;
        ESP_LOGI(TAG_AP, "Station "MACSTR" joined, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data;
        ESP_LOGI(TAG_AP, "Station " MACSTR " left, AID=%d, reason:%d",
                 MAC2STR(event->mac), event->aid, event->reason);
    }
}

/**
 * @brief Register WiFi AP event handlers
 */
void wifi_ap_register_event_handlers(void)
{
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                    ESP_EVENT_ANY_ID,
                    &wifi_ap_event_handler,
                    NULL,
                    NULL));
}

/**
 * @brief Set DNS address for softAP
 *
 * @param esp_netif_ap AP network interface
 * @param esp_netif_sta STA network interface
 */
void softap_set_dns_addr(esp_netif_t *esp_netif_ap, esp_netif_t *esp_netif_sta)
{
    esp_netif_dns_info_t dns;
    esp_netif_get_dns_info(esp_netif_sta, ESP_NETIF_DNS_MAIN, &dns);
    uint8_t dhcps_offer_option = DHCPS_OFFER_DNS;
    ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(esp_netif_ap));
    ESP_ERROR_CHECK(esp_netif_dhcps_option(esp_netif_ap, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_offer_option, sizeof(dhcps_offer_option)));
    ESP_ERROR_CHECK(esp_netif_set_dns_info(esp_netif_ap, ESP_NETIF_DNS_MAIN, &dns));
    ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(esp_netif_ap));
}

/**
 * @brief Enable NAPT on the AP netif
 *
 * @param esp_netif_ap AP network interface
 */
void wifi_ap_enable_napt(esp_netif_t *esp_netif_ap)
{
    /* Enable napt on the AP netif */
    if (esp_netif_napt_enable(esp_netif_ap) != ESP_OK) {
        ESP_LOGE(TAG_AP, "NAPT not enabled on the netif: %p", esp_netif_ap);
    }
}